#include "./utils/store.h"
#include "./device/compat.h"

using namespace driver;
using Error = utils::Error;

struct Info {
    uint32_t pkg_size;
    uint32_t ota_addr;
    uint32_t app_addr;

    void init(uint32_t size) {
        pkg_size = size;
        ota_addr = flash::OtaDataAddr;
        app_addr = flash::AppAddr;
    }

    bool verify() const {
        return ((pkg_size > 0) && 
                (pkg_size < flash::OtaDataSize) && 
                (app_addr == flash::AppAddr) &&
                (ota_addr == flash::OtaDataAddr));
    }

    void reset() {
        pkg_size = 0;
        ota_addr = 0;
        app_addr = 0;
    }
};

static utils::Store<Info, flash::OtaInfoAddr> info;

void runApp() {

	auto sp = *reinterpret_cast<const volatile uint32_t *>(flash::AppAddr);
	auto pc = *reinterpret_cast<const volatile uint32_t *>(flash::AppAddr + 4);
	auto app = reinterpret_cast<void (*)(void)>(pc);
	__set_MSP(sp);
	app();	    
}

void runOta() {
    flash::Move(flash::AppAddr, flash::OtaDataAddr, info->pkg_size);
    info.Erase();
}

int main() {
	Error err = info.Load();
    if (err.IsOk() && info->verify()) {
        runOta();
    }
    runApp();
}
